package cn.stylefeng.guns.cloud.workflow.modular.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.cloud.libs.mp.page.PageFactory;
import cn.stylefeng.guns.cloud.model.page.PageResult;
import cn.stylefeng.guns.cloud.workflow.core.util.TimeCalcUtil;
import cn.stylefeng.guns.cloud.workflow.modular.model.params.RunOrEndProcessParam;
import cn.stylefeng.guns.cloud.workflow.modular.model.result.EndProcessResult;
import cn.stylefeng.guns.cloud.workflow.modular.service.EndProcessService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.history.*;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 已结束流程 服务实现类
 *
 * @Author xuyuxiang
 * @Date 2019/11/14 17:25
 **/
@Service
public class EndProcessServiceImpl implements EndProcessService {

    private final String APPLY_USER_NAME = "applyUserName";

    private final String APPLY_DATE = "applyDate";

    private final String APPLY_USER_ID = "applyUserId";

    private final String COMPLETED = "completed";

    private final String END = "end";

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    /**
     * 已结束的流程
     *
     * @Author xuyuxiang
     * @Date 2019/11/14 17:42
     **/
    @Override
    public PageResult list(RunOrEndProcessParam endProcessParam) {

        Page pageContext = this.getPageContext();

        List<HistoricTaskInstance> taskList = this.getEndTaskInstanceList(endProcessParam, pageContext);
        long count = this.countEndTaskInstance(endProcessParam);

        //将任务转换成EndProcessResult
        List<EndProcessResult> taskModelList = this.copyEndTaskListInfo(taskList);
        pageContext.setRecords(taskModelList);
        pageContext.setTotal(count);
        return new PageResult(pageContext);
    }

    /**
     * 获取已结束任务实例列表
     *
     * @Author xuyuxiang
     * @Date 2019/11/14 17:45
     **/
    private List<HistoricTaskInstance> getEndTaskInstanceList(RunOrEndProcessParam endProcessParam, Page pageContext) {
        HistoricProcessInstanceQuery historicProcessInstanceQuery = this.getEndTaskProcessInstanceQuery(endProcessParam);
        //获取历史流程实体列表
        List<HistoricProcessInstance> historicProcessInstanceList = historicProcessInstanceQuery.listPage((int) pageContext.getSize() * ((int) pageContext.getCurrent() - 1),
                (int) pageContext.getSize());
        //定义返回的任务历史流程实体列表
        List<HistoricTaskInstance> historicTaskInstanceList = new ArrayList<>();
        //获取最新任务节点信息
        for (HistoricProcessInstance historicProcessInstance : historicProcessInstanceList) {
            String processInstanceId = historicProcessInstance.getId();
            //获取historicTaskInstanceQuery
            HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService
                    .createHistoricTaskInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .orderByTaskCreateTime()
                    .desc();
            HistoricTaskInstance historicTaskInstance = historicTaskInstanceQuery.list().get(0);
            historicTaskInstanceList.add(historicTaskInstance);

        }
        return historicTaskInstanceList;
    }

    /**
     * 获取已结束流程HistoricProcessInstanceQuery
     *
     * @Author xuyuxiang
     * @Date 2019/11/14 18:19
     **/
    private HistoricProcessInstanceQuery getEndTaskProcessInstanceQuery(RunOrEndProcessParam endProcessParam) {
        HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery();

        String processName = endProcessParam.getProcessName();
        //根据流程名称查询
        if (ObjectUtil.isNotEmpty(processName)) {
            //根据流程名称查询流程定义实例集合
            ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionNameLike("%" + processName + "%");
            List<ProcessDefinition> processDefinitionList = processDefinitionQuery.list();
            //获取流程定义实例的key集合
            Set<String> processKeySet = new HashSet<>();
            for (ProcessDefinition processDefinition : processDefinitionList) {
                String key = processDefinition.getKey();
                processKeySet.add(key);
            }
            List<String> processKeyList = new ArrayList<>(processKeySet);
            historicProcessInstanceQuery.processDefinitionKeyIn(processKeyList);
        }
        //根据申请人查询
        String applyUserId = endProcessParam.getApplyUserId();

        if (ObjectUtil.isNotEmpty(applyUserId)) {
            historicProcessInstanceQuery.startedBy(applyUserId);
        }
        //流程已结束的
        historicProcessInstanceQuery.finished();

        return historicProcessInstanceQuery;
    }

    /**
     * 获取已结束任务实例数量
     *
     * @Author xuyuxiang
     * @Date 2019/11/14 17:46
     **/
    private long countEndTaskInstance(RunOrEndProcessParam endProcessParam) {
        return this.getEndTaskProcessInstanceQuery(endProcessParam).count();
    }

    /**
     * 将结果转换为EndProcessResult
     *
     * @Author xuyuxiang
     * @Date 2019/11/14 17:46
     **/
    private List<EndProcessResult> copyEndTaskListInfo(List<HistoricTaskInstance> taskList) {
        //返回的EndProcessResult集合
        List<EndProcessResult> endProcessResultList = new ArrayList<>();

        for (HistoricTaskInstance historicTaskInstance : taskList) {
            //任务id
            String taskId = historicTaskInstance.getId();

            //获取流程定义id
            String processDefinitionId = historicTaskInstance.getProcessDefinitionId();
            //获取流程定义实例
            ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
            //获取流程名称
            String processDefinitionName = processDefinition.getName();
            //流程实例id
            String processInstanceId = historicTaskInstance.getProcessInstanceId();

            //获取参数列表
            String applyUserId = "-";
            String applyUserName = "-";
            String applyDate = "-";
            List<HistoricVariableInstance> historicVariableInstanceList = historyService
                    .createHistoricVariableInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .list();
            for (HistoricVariableInstance historicVariableInstance : historicVariableInstanceList) {
                //获取参数名称
                String variableName = historicVariableInstance.getVariableName();
                //取出参数
                if (APPLY_USER_ID.equals(variableName)) {
                    //申请人id
                    applyUserId = historicVariableInstance.getValue().toString();
                }
                if (APPLY_USER_NAME.equals(variableName)) {
                    //申请人姓名
                    applyUserName = (String) historicVariableInstance.getValue();
                }
                if (APPLY_DATE.equals(variableName)) {
                    //申请人时间
                    applyDate = (String) historicVariableInstance.getValue();
                }

            }

            //开始时间，此处开始时间为用户申请时间
            String startTime = applyDate;

            //流程结束，因当前任务节点为该流程的最后节点，故结束时间为当前任务节点的结束时间
            Date tempEndTime = historicTaskInstance.getEndTime();
            String endTime = DateUtil.formatDateTime(tempEndTime);

            //结束原因
            String endReason = "-";
            //删除原因
            String deleteReason = historicTaskInstance.getDeleteReason();
            boolean isSameUser = applyUserId.equals(historicTaskInstance.getAssignee());

            //如果结束原因为completed,否则为异常结束，操作人不是申请人，则表示正常结束，否则为用户取消申请
            if (COMPLETED.equals(deleteReason)) {
                if (!isSameUser) {
                    endReason = "正常结束";
                } else {
                    endReason = "取消申请";
                }
            } else if (END.equals(deleteReason)) {
                endReason = "强制终止";
            } else {
                endReason = "异常结束";
            }

            //耗时时间，若流程结束，此处耗时时间为用户申请时间与流程结束时间差，流程运行则时间不展示
            String duration = "-";

            long between = DateUtil.between(DateUtil.parseDateTime(startTime), DateUtil.parseDateTime(endTime), DateUnit.MS);
            duration = TimeCalcUtil.calc(between);

            //待办任务标题
            String taskTitle = processDefinitionName + "(" + applyUserName + " " + applyDate + ")";

            //创建
            EndProcessResult endProcessResult = new EndProcessResult();
            endProcessResult.setTaskId(taskId);
            endProcessResult.setProcessDefinitionId(processDefinitionId);
            endProcessResult.setProcessInstanceId(processInstanceId);
            endProcessResult.setTaskTitle(taskTitle);
            endProcessResult.setProcessName(processDefinitionName);
            endProcessResult.setApplyUserId(applyUserId);
            endProcessResult.setApplyUserName(applyUserName);
            endProcessResult.setApplyDate(applyDate);
            endProcessResult.setStartTime(startTime);
            endProcessResult.setEndTime(endTime);
            endProcessResult.setDuration(duration);
            endProcessResult.setEndReason(endReason);
            endProcessResultList.add(endProcessResult);
        }
        return endProcessResultList;
    }

    /**
     * 获取pageContext
     *
     * @Author xuyuxiang
     * @Date 2019/10/25 16:04
     **/
    private Page getPageContext() {
        return PageFactory.defaultPage();
    }

}
